#ifndef _XM_H_
#define _XM_H_
#include "agbmusic.h"
#include "file/file.h"
#include "file/file_mem.h"

#include <math.h>

/*
读取或写入xm文件
*/

typedef struct __attribute__ ((__packed__)){
    u16 ordnum;     //一个多少个ord
    u16 restart;
    u16 channum;    //声道
    u16 patnum;     //42pat,包括0
    u16 insnum;     //乐器数量
    u16 freqtab;    //1

    //位置会出错?
    u16 speed;      //速度160
    u16 tempo;      //节奏8

    u8  ord[256];   //ord数据,最大是256,乐器最大是255 , ord对应的pat排序
}xm_head_t;

//104版本
typedef struct __attribute__ ((__packed__)){
    //Pattern
    u32  len;   //pattern长度,一般为 sizeof(xm_pattern_t)
    u8   type;  //类型
    u16  rows;  //rows长度
    u16  patdata;   //buffer数据长度
    u8   buffer[0];    //数据缓存
}xm_pattern_t;

//
typedef struct __attribute__ ((__packed__)){
    u16 env1;
    u16 env2;   //会处理成<<=2
}insn_env_t;

typedef struct __attribute__ ((__packed__)){
    insn_env_t venv[12];    //声音封装
    insn_env_t penv[12];    //
    u8 venv_num,penv_num;
    u8 vsustain;
    u8 vloops;
    u8 vloope;
    u8 psustain;
    u8 ploops;
    u8 ploope;
    u8 vtype;
    u8 ptype;
    u8 vibtype;
    u8 vibsweep;
    u8 vibdepth;    // <<=1
    u8 vibrate;
    u16 volfade;    // <<=1
}insData_t;

typedef struct __attribute__ ((__packed__)){
    u32     samplen;    //样本长度,如果样本长度为不为0，则存在数据
    u32     loopstart;  //循环开始
    u32     looplen;    //循环长度
    u8      vol;        //样本音量，最大为64,默认64
    u8      finetune;   //微调,默认0
    u8      type;       //类型 , 0x10:表示16bit数据?, 默认为1?,只有两种类型，一种是ADPCM，另一种是DELTA
    u8      pan;        //默认为100 (0x64)
    u8      relnote;    //0:(C-5) 1:(C#5)...
    //39 (relnote:A-9) + 13(note:C-2) = 52
    u8      res;        //如果是0xad，则表示是adpcm，否则是DELTA (PCM)
    char    name[22];
    u8      data[0];
}xm_samplen_t;

typedef struct __attribute__ ((__packed__)){
    u32     size;           //大小
    char    name[22];
    u8      type;
    u16     samp;           //最大样本数为96,默认1
    u32     shsize;         //sh大小? 0x28
    /*
    一般缓存大小为 insn.size - 33,一般为
    insn_venv_t venv[12]
    insn_penv_t penv[12]
    接着
    */
    u8          insData[230];   //
    xm_samplen_t samp_data[0];       //数量为insn.samp
}xm_insn_t;

enum{
    xm_insn_sizeof = sizeof(xm_insn_t),
};

typedef struct __attribute__ ((__packed__)){
    u8  sig[17];    //"Extended Module: "
    u8  name[20];
    u8  wthis1a;    //0x1a
    u8  editor[20]; //编辑器
    u16 version;    //版本,0x0104
    u32 hdrsize;    //头大小 0x114, -4
    //xm_head_t
    xm_head_t       header;
    xm_pattern_t    pat[0];     //数量为header.patnum
    xm_insn_t       insn[0];    //数量为header.insnum
}xm_t;


static int xm_gen_insn(file_t*file,u32 addr,u8 *wav_p,int wav_size,int rate,int relnote,int finetune,int loopstart,int loopend){
    s8*wav = (s8*)wav_p;
    //乐器
    xm_insn_t insn;
    memset(&insn,0,sizeof(insn));
    sprintf(insn.name,"%X",addr);
    insn.size = 0x107;  //insn_t 大小
    insn.samp = 1;  //一个样本
    insn.shsize = 0x28;
    file_write(&insn,sizeof(insn),1,file);

    xm_samplen_t sm;
    memset(&sm,0,sizeof(sm));
    sm.vol = 64;
    sm.samplen = wav_size;
    sm.type = 0|1;    //使用delta
    sm.res = 0;
    sm.pan = 100;
    sm.relnote = relnote;
    sm.finetune = finetune;
    sm.loopstart = loopstart;
    sm.looplen = loopend - loopstart;

    // sm.pan = 128;
    // sm.finetune = 17;
    // sm.relnote = 8;

    sprintf(sm.name,"%X",addr);
    file_write(&sm,sizeof(sm),1,file);
    s8 b1 = 0;
    int i = 0;
    b1 = wav[0];
    for(i=wav_size-1;i>0;i--){
        wav[i] = wav[i] - wav[i-1];
    }
    file_write(wav,wav_size,1,file);

    b1 = 0;
    for(i=0;i<wav_size;i++){
        wav[i] = b1+=wav[i];
    }
}

static int _xm_write_d(FILE*file,file_t*d){
    int sz = file_tell(d);
    file_seek(d,0,SEEK_SET);
    u8 buf[BUFSIZ];
    while(sz>=BUFSIZ){
        file_read(buf,BUFSIZ,1,d);
        fwrite(buf,BUFSIZ,1,file);
        sz -= BUFSIZ;
    }
    if(sz>0){
        file_read(buf,sz,1,d);
        fwrite(buf,sz,1,file);
        sz -= sz;
    }
    return 0;
}

static int _xm_write_dd(file_t*file,file_t*d){
    int sz = file_tell(d);
    file_seek(d,0,SEEK_SET);
    u8 buf[BUFSIZ];
    while(sz>=BUFSIZ){
        file_read(buf,BUFSIZ,1,d);
        file_write(buf,BUFSIZ,1,file);
        sz -= BUFSIZ;
    }
    if(sz>0){
        file_read(buf,sz,1,d);
        file_write(buf,sz,1,file);
        sz -= sz;
    }
    return 0;
}

static void xm_gen_pat(file_t*file,file_t*p,int rows){
    xm_pattern_t pat;
    //memset(&pat,0,sizeof(pat));
    pat.len = sizeof(pat);
    pat.rows = rows;
    pat.type = 0;
    //pat.patdata = 0;//没有数据
    pat.patdata = file_tell(p);
    file_write(&pat,sizeof(pat),1,file);
    _xm_write_dd(file,p);
    file_seek(p,0,SEEK_SET);
}

static int xm_gen(FILE*file,file_t*insn_file,int insn_num,int channum,file_t*pat_file,int patnum,int tempo){
    xm_t xm;
    memset(&xm,0,sizeof(xm));
    sprintf(xm.sig,"Extended Module: ");
    sprintf(xm.name,"xxxx");
    sprintf(xm.editor,"xxxx");
    xm.wthis1a = 0x1a;
    xm.version = 0x104;
    xm.hdrsize = 0x114;
    xm.header.insnum = insn_num;
    //xm.header.channum = 6;
    xm.header.channum = channum;    //声道数量
    xm.header.ordnum = patnum;
    xm.header.patnum = patnum;      //最大255
    xm.header.freqtab = 1;
    if(tempo>32){
        //最小值为32
        xm.header.tempo = tempo;
        xm.header.speed = 1;
    }
    else{
        xm.header.speed = 1;
        while(tempo<32){
            tempo *= 2;
            xm.header.speed *= 2;
        }
        xm.header.tempo = tempo;
    }

    //有时候，需要speed==3
    while(xm.header.speed<2){
        xm.header.tempo *= 2;
        xm.header.speed *= 2;
    }

    int i;
    for(i=0;i<patnum;i++){
        xm.header.ord[i] = i;
    }

    //写入头信息


    if(file_tell(pat_file)){
        fwrite(&xm,sizeof(xm),1,file);
        _xm_write_d(file,pat_file);
    }
    else{
        //空的pat
        xm.header.patnum = 1;
        xm.header.ordnum = 1;
        fwrite(&xm,sizeof(xm),1,file);
        xm_pattern_t pat;
        pat.len = sizeof(pat);
        pat.rows = 256;
        pat.type = 0;
        pat.patdata = 0;    //没有数据
        fwrite(&pat,sizeof(pat),1,file);
    }

    //写入乐器数据
    _xm_write_d(file,insn_file);

    return 0;
}

// static int xm_track_wait(file_t*file,u32){

// }

enum{
    xm_Cn1 = 1,
    xm_Cs1,
    xm_Dn1,
    xm_Ds1,
    xm_En1,
    xm_Fn1,
    xm_Fs1,
    xm_Gn1,
    xm_Gs1,
    Xm_An1,
    Xm_As1,
    Xm_Bn1,

    xm_Cn2,
    xm_Cs2,
    xm_Dn2,
    xm_Ds2,
    xm_En2,
    xm_Fn2,
    xm_Fs2,
    xm_Gn2,
    xm_Gs2,
    Xm_An2,
    Xm_As2,
    Xm_Bn2,


    xm_Cn3,
    xm_Cs3,
    xm_Dn3,
    xm_Ds3,
    xm_En3,
    xm_Fn3,
    xm_Fs3,
    xm_Gn3,
    xm_Gs3,
    Xm_An3,
    Xm_As3,
    Xm_Bn3,


    xm_Cn4,
    xm_Cs4,
    xm_Dn4,
    xm_Ds4,
    xm_En4,
    xm_Fn4,
    xm_Fs4,
    xm_Gn4,
    xm_Gs4,
    Xm_An4,
    Xm_As4,
    Xm_Bn4,


    xm_Cn5,
    xm_Cs5,
    xm_Dn5,
    xm_Ds5,
    xm_En5,
    xm_Fn5,
    xm_Fs5,
    xm_Gn5,
    xm_Gs5,
    Xm_An5,
    Xm_As5,
    Xm_Bn5,

    xm_Cn6,     //60
    xm_Cs6,
    xm_Dn6,
    xm_Ds6,
    xm_En6,
    xm_Fn6,
    xm_Fs6,
    xm_Gn6,
    xm_Gs6,
    Xm_An6,
    Xm_As6,
    Xm_Bn6,

    xm_Cn7,
    xm_Cs7,
    xm_Dn7,
    xm_Ds7,
    xm_En7,
    xm_Fn7,
    xm_Fs7,
    xm_Gn7,
    xm_Gs7,
    Xm_An7,
    Xm_As7,
    Xm_Bn7,

    xm_Cn8,
    xm_Cs8,
    xm_Dn8,
    xm_Ds8,
    xm_En8,
    xm_Fn8,
    xm_Fs8,
    xm_Gn8,
    xm_Gs8,
    Xm_An8,
    Xm_As8,
    Xm_Bn8,

    xm_Cn9,
    xm_Cs9,
    xm_Dn9,
    xm_Ds9,
    xm_En9,
    xm_Fn9,
    xm_Fs9,
    xm_Gn9,
    xm_Gs9,
    Xm_An9,
    Xm_As9,
    Xm_Bn9,

    xm_Cn10,
    xm_Cs10,
    xm_Dn10,
    xm_Ds10,
    xm_En10,
    xm_Fn10,
    xm_Fs10,
    xm_Gn10,
    xm_Gs10,
    Xm_An10,
    Xm_As10,
    Xm_Bn10,

};

enum{
    xm_portamento_max = 64, //0x40
};

/*
有关线性表的频率
    floor(8363*64*pow(2,-n/768))
    8363为c5speed (xm的默认速度)
    64  每个音高分成64份 (一个音阶单位为64 * 12)
    n   为输入的period  (period 为(NOTE_MAX - note) * 64)
    768 表示音阶分成768份 (注:半音阶表示分成12个音高，Cn1~Bs1)
    period =((NOTE_MAX - note) * 64) - (fineTune / 2)
        fineTune的范围应该是-128~127


agb的bend,bendr 转换成
    mid:  bend
    xm :  portamento

有关portamento的参数
    每个音程为(64 / 4), 也就是说Cn1-Cs1 分成 16份
    如果xm的speed为1时，它不会处理portamento
    当speed为2时，会处理一次portamento
    当speed为3时，会处理两次portamento
        (注，遇到第一个tick，不会处理portamento事件)

    当执行一个 (row) (portamento事件)，处理的次数如下
        portamento次数 = speed - 1


*/

#endif